package cn.xinfei.xdecision.data.core.frame.executors.collect.credit;

import cn.xinfei.xdecision.common.model.datax.consts.VariableConst;
import cn.xinfei.xdecision.common.model.datax.enums.*;
import cn.xinfei.xdecision.common.model.datax.exception.XDecisionDataException;
import cn.xinfei.xdecision.common.model.datax.exception.XDecisionDataExceptionType;
import cn.xinfei.xdecision.data.core.context.ContextHolder;
import cn.xinfei.xdecision.data.core.frame.executors.collect.AbstractCollectService;
import cn.xinfei.xdecision.data.core.frame.executors.collect.VarHandlerChain;
import cn.xinfei.xdecision.data.core.frame.executors.collect.handler.*;
import cn.xinfei.xdecision.data.core.frame.strategy.credit.CreditStrategy;
import cn.xinfei.xdecision.data.core.frame.strategy.StrategyContext;
import cn.xinfei.xdecision.data.core.util.VariableConvertUtil;
import cn.xinfei.xdecision.data.core.vo.VarCollectAwareVO;
import cn.xinfei.xdecision.data.core.vo.credit.CreditStatusDTO;
import cn.xinfei.xdecision.data.core.vo.credit.CreditStatusRequest;
import cn.xinfei.xdecision.model.VariableApiRequest;
import cn.xinfei.xdecision.model.VariableApiResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;


@Slf4j
@Service
public class CreditCollectService extends AbstractCollectService implements ICreditCollect {

    @Autowired
    VarDispatchExecutorHandler varDispatchExecutorHandler;
    @Autowired
    VarRuteDataSourceHandler varRuteDataSourceHandler;

    @Autowired
    VarInputParamVerifyHandler varInputParamVerifyHandler;

    @Autowired
    VarApiAndVariablesHandler varApiAndVariablesHandler;

    @Autowired
    StrategyContext strategyContext;

    @Autowired
    ApplicationContext applicationContext;


    @Override
    public VariableApiResponse creditCollect(VariableApiRequest variableApiRequest) {

        varCollectInputCheck(variableApiRequest);
        varCreditChannelCheck(variableApiRequest);

        VarCollectAwareVO varCollectAwareVO = new VarCollectAwareVO();
        VariableApiResponse variableApiResponse = new VariableApiResponse();
        variableApiResponse.setRequestId(variableApiRequest.getRequestId());

        varCollectAwareVO.setRequestId(variableApiRequest.getRequestId());
        varCollectAwareVO.setVarCodes(variableApiRequest.getVarCodes());
        varCollectAwareVO.setInputPrarams(variableApiRequest.getInputParams());
        varCollectAwareVO.setCollectStageEnum(CollectStageEnum.REAL_TIME_COLLECT);
        VarHandlerChain varHandler = new VarHandlerChain();
        varHandler
                .addHandler(varInputParamVerifyHandler)
                .addHandler(varApiAndVariablesHandler)
                .addHandler(varRuteDataSourceHandler)
                .addHandler(varDispatchExecutorHandler);

        varHandler.doHandle(varCollectAwareVO);
        variableApiResponse.setVariablesResponse(JSONObject.toJSONString(varCollectAwareVO.getExecutorResultMap(), SerializerFeature.WRITE_MAP_NULL_FEATURES, SerializerFeature.QuoteFieldNames));
        variableApiResponse.setStage(varCollectAwareVO.getCollectStageEnum().name());

        return variableApiResponse;
    }

    @Override
    public VariableApiResponse fetchCreditVars(VariableApiRequest variableApiRequest) {

        varCollectInputCheck(variableApiRequest);
        varCreditChannelCheck(variableApiRequest);
        buildVarContext(variableApiRequest.getInputParams());

        VariableApiResponse variableApiResponse = new VariableApiResponse();
        variableApiResponse.setRequestId(variableApiRequest.getRequestId());

        CreditStrategy creditStrategy = (CreditStrategy) strategyContext.getStrategy(VariableStrategyType.CREDIT.name());
        JSONObject inputParams = variableApiRequest.getInputParams();

        CreditStatusDTO statusDTO = VariableConvertUtil.fromVariableApiRequest(variableApiRequest);

        String creditChannel = inputParams.getString(VariableConst.CREDIT_CHANNEL);
        log.info("requestId: {} creditChannel = {}", variableApiRequest.getRequestId(), creditChannel);
        statusDTO.setCreditChannel(creditChannel);
        statusDTO.setInputParams(inputParams);
        ContextHolder.getCurrentContext().add(VariableConst.CREDIT_CHANNEL, creditChannel);

        JSONObject statusResponse = creditStrategy.status(buildCreditStatusRequest(inputParams, creditChannel), inputParams);
        String status = statusResponse.getString("inquiry_status");
        String code = StringUtils.isBlank(status) ? statusResponse.getString("code") : status;
        CreditInquiryStatus inquiryStatus = EnumUtil.fromCodeOrThrow(CreditInquiryStatus.class, code);

        JSONObject creditChannelJson = new JSONObject();
        creditChannelJson.fluentPut(VariableConst.CREDIT_CHANNEL, creditChannel);
        switch (inquiryStatus) {
            case INIT:
                log.info("requestId: {} 人行报告正在初始化", variableApiRequest.getRequestId());
                variableApiResponse.setCode(inquiryStatus.getCode());
                variableApiResponse.setMessage(CreditInquiryStatus.INIT.getDesc());
                variableApiResponse.setStage(CollectStageEnum.REAL_TIME_COLLECT.name());
                variableApiResponse.setVariablesResponse(creditChannelJson.toJSONString());
//                log.info("requestId: {} 异步拉起征信查询任务，请勿频繁查询！", variableApiRequest.getRequestId());
//                applicationContext.publishEvent(new CreditQueryEvent(
//                        this, statusDTO));
                break;
            case QUERYING:
                log.info("requestId: {} 人行报告查询中", variableApiRequest.getRequestId());
                variableApiResponse.setCode(inquiryStatus.getCode());
                variableApiResponse.setMessage(CreditInquiryStatus.QUERYING.getDesc());
                variableApiResponse.setStage(CollectStageEnum.REAL_TIME_COLLECT.name());
                variableApiResponse.setVariablesResponse(creditChannelJson.toJSONString());
//                log.info("requestId: {} 异步拉起征信查询任务，请勿频繁查询！", variableApiRequest.getRequestId());
//                applicationContext.publishEvent(new CreditQueryEvent(
//                        this, statusDTO));
                break;
            case QUERY_FAIL:
                log.info("requestId: {} 人行报告查询失败", variableApiRequest.getRequestId());
                variableApiResponse.setCode(inquiryStatus.getCode());
                variableApiResponse.setMessage(CreditInquiryStatus.QUERY_FAIL.getDesc());
                variableApiResponse.setStage(CollectStageEnum.REAL_TIME_COLLECT.name());
                variableApiResponse.setVariablesResponse(creditChannelJson.toJSONString());
                break;
            case QUERY_SUCCESS:
                log.info("requestId: {} 人行报告拉取成功，开始计算人行变量", variableApiRequest.getRequestId());
                variableApiResponse.setCode(inquiryStatus.getCode());
                variableApiResponse = this.creditCollect(variableApiRequest);
                JSONObject responseJson = JSONObject.parseObject(variableApiResponse.getVariablesResponse(), JSONObject.class);
                responseJson.fluentPut(VariableConst.CREDIT_CHANNEL, creditChannel);
                variableApiResponse.setVariablesResponse(JSON.toJSONString(responseJson, SerializerFeature.WriteMapNullValue, SerializerFeature.QuoteFieldNames));
                variableApiResponse.setMessage(CreditInquiryStatus.QUERY_SUCCESS.getDesc());
                break;
            case OVERDUE:
                log.info("requestId: {} 人行报告已经过期", variableApiRequest.getRequestId());
                variableApiResponse.setCode(inquiryStatus.getCode());
                variableApiResponse.setMessage(CreditInquiryStatus.OVERDUE.getDesc());
                variableApiResponse.setStage(CollectStageEnum.REAL_TIME_COLLECT.name());
                variableApiResponse.setVariablesResponse(creditChannelJson.toJSONString());
                break;
            case EMPTY:
                log.info("requestId: {} 人行报告记录为空", variableApiRequest.getRequestId());
                variableApiResponse.setCode(inquiryStatus.getCode());
                variableApiResponse.setMessage(CreditInquiryStatus.EMPTY.getDesc());
                variableApiResponse.setStage(CollectStageEnum.REAL_TIME_COLLECT.name());
                variableApiResponse.setVariablesResponse(creditChannelJson.toJSONString());
                break;
            default:
                throw new XDecisionDataException(
                        XDecisionDataExceptionType.DATA_NO_SUCH_CREDIT_STATUS_TYPE_ERROR,
                        XDecisionDataExceptionType.DATA_NO_SUCH_CREDIT_STATUS_TYPE_ERROR.text
                );
        }

        return variableApiResponse;
    }

    private CreditStatusRequest buildCreditStatusRequest(JSONObject params, String creditChannel) {
        CreditStatusRequest creditStatusRequest = new CreditStatusRequest();
        creditStatusRequest.setMobile(params.getString(VariableConst.MOBILE));
        creditStatusRequest.setCreditChannel(creditChannel);
        creditStatusRequest.setIdCardNumber(params.getString(VariableConst.ID_CARD_NUMBER));
        creditStatusRequest.setStage((String)params.getOrDefault(VariableConst.STAGE,"01"));
        creditStatusRequest.setName(params.getString(VariableConst.NAME));
        return creditStatusRequest;
    }
}
